/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#include "StdAfx.h"
#include "MKMcast4List.h"

#include "MAddressIP.h"

//---------------------------------------------------------------------------

MKMcast4List::MKMcast4List(void)
{
	processIana = false;
}

MKMcast4List::~MKMcast4List(void)
{
	CleanUp();
}

//---------------------------------------------------------------------------

void MKMcast4List::CleanUp(void)
{
	MKMcast4 *elem;

	for(itor=theVector.begin(); itor!=theVector.end(); itor++){
		elem = *itor;
		if(elem!=NULL){
			*itor = NULL;
			delete elem;
		}
	}
	theVector.clear();
}

//---------------------------------------------------------------------------

MKMcast4* MKMcast4List::CreateElement(void)
{
	MKMcast4 *elem;

	try{
		elem = new MKMcast4;
	}
	catch(...){
		elem = NULL;
	}
	return elem;
}

bool MKMcast4List::AddElement(MKMcast4* elemIn)
{
	MKMcast4 *elem;
	int cnt;

	if(elemIn==NULL) return true;

	elem = CreateElement();
	if(elem==NULL) return false;

	elem->LoadFromPointer(elemIn);

	cnt = (int)theVector.size();
	theVector.push_back(elem);
	cnt = (int)theVector.size() - cnt;
	if(cnt!=1){
		delete elem;
		return false;
	}

	return true;
}

bool MKMcast4List::AddElement(DWORD asIn, DWORD aeIn, CString nameIn)
{
	MKMcast4 elem;

	elem.assignedTo = nameIn;
	elem.addrStart  = asIn;
	elem.addrEnd    = aeIn;

	return AddElement(&elem);
}

//---------------------------------------------------------------------------

void MKMcast4List::Initialize(void)
{
	CleanUp();
}

//---------------------------------------------------------------------------

bool MKMcast4List::Add(MKMcast4* miIn)
{
	return AddElement(miIn);
}

//---------------------------------------------------------------------------

void MKMcast4List::Clear(void)
{
	CleanUp();
}

//---------------------------------------------------------------------------

int MKMcast4List::GetSize(void)
{
	return (int)theVector.size();
}

MKMcast4* MKMcast4List::GetByIdx(int idxIn)
{
	if(idxIn<0)          return NULL;
	if(idxIn>=GetSize()) return NULL;

	return theVector[idxIn];
}

//---------------------------------------------------------------------------

CString MKMcast4List::GetName(DWORD addrIn, bool reportUnknown)
{
	MKMcast4 *elem;
	CString str;
	bool found;

	found = false;
	for(itor=theVector.begin(); itor!=theVector.end() && !found; itor++){
		elem = *itor;
		if(elem!=NULL){
			if(elem->AddressIsMember(addrIn)){
				str = elem->assignedTo;
				found = true;
			}
		}
	}

	if(!found)
		if(reportUnknown) str = _T("- unknown -");
		else              str.Empty();

	return str;
}

//---------------------------------------------------------------------------

bool MKMcast4List::LoadFromIanaFile(CString strIn)
{
	processIana = true;

	return LoadFromFile(strIn);
}

bool MKMcast4List::LoadFromMyFile(CString strIn)
{
	processIana = false;

	return LoadFromFile(strIn);
}

//---------------------------------------------------------------------------

void MKMcast4List::InternalInit(void)
{
	Initialize();
}

//---------------------------------------------------------------------------

bool MKMcast4List::InternalProcessIanaLine(char* buf)
{
	CString str;
	CString strAddr, sas, sae;
	CString strName;
	MAddressIP addr;
	DWORD dwAs, dwAe;
	int pos;
	in_addr ia;

	str = buf;

	if(str.GetLength()<9)
		return false; /* xxx.x.x.x */

	strAddr = str.Left(1);
	if(strAddr.CompareNoCase(_T("#"))==0){
		// comment line
		return false;
	}

	pos = str.Find(' ', 0);
	if(pos==-1){
		// no name ? -> reject the line
		return false;
	}

	strAddr = str.Left(pos);
	strName = str.Mid(pos+1);

	pos = strAddr.Find('-', 0);
	if(pos!=-1){
		// it is a range
		sas = strAddr.Left(pos);
		sae = str.Mid(pos+1);
	}
	else{
		// a single address
		sas = strAddr;
		sae = strAddr;
	}

	sas = sas.Trim();
	sae = sae.Trim();

	addr.Set(sas);
	dwAs = addr.GetD();
	addr.Set(sae);
	dwAe = addr.GetD();

	ia.S_un.S_addr = dwAs;
	if(ia.S_un.S_un_b.s_b1<224){
		OutputDebugString(str);
		return false;
	}
	if(ia.S_un.S_un_b.s_b1>239){
		OutputDebugString(str);
		return false;
	}

	ia.S_un.S_addr = dwAe;
	if(ia.S_un.S_un_b.s_b1<224){
		OutputDebugString(str);
		return false;
	}
	if(ia.S_un.S_un_b.s_b1>239){
		OutputDebugString(str);
		return false;
	}

	pos = strName.Find('[', 0);
	if(pos!=-1)
		strName = strName.Left(pos);
	strName.Trim();

	return AddElement(dwAs, dwAe, strName);
}

bool MKMcast4List::InternalProcessMyLine(char* buf)
{
	CString str;
	CString strAddr, sas, sae;
	CString strName;
	MAddressIP addr;
	DWORD dwAs, dwAe;
	int pos;
	in_addr ia;

	str = buf;

	if(str.GetLength()<21) return false; // xxx.x.x.x-xxx.x.x.x a

	pos = str.Find(' ', 0);
	if(pos==-1) return false; // no name ? -> reject the line

	strAddr = str.Left(pos);
	strName = str.Mid(pos+1);

	pos = strAddr.Find('-', 0);
	if(pos==-1) return false;

	sas = strAddr.Left(pos);
	sae = str.Mid(pos+1);

	addr.Set(sas);
	dwAs = addr.GetD();
	addr.Set(sae);
	dwAe = addr.GetD();

	ia.S_un.S_addr = dwAs;
	if(ia.S_un.S_un_b.s_b1<224) return false;
	if(ia.S_un.S_un_b.s_b1>239) return false;

	ia.S_un.S_addr = dwAe;
	if(ia.S_un.S_un_b.s_b1<224) return false;
	if(ia.S_un.S_un_b.s_b1>239) return false;

	strName = strName.Trim();

	return AddElement(dwAs, dwAe, strName);
}

bool MKMcast4List::InternalProcessLine(char* buf)
{
	if(buf==NULL){
		// nothing to process
		return true;
	}

	if(processIana) return InternalProcessIanaLine(buf);

	return InternalProcessMyLine(buf);
}

//---------------------------------------------------------------------------

bool MKMcast4List::InternalSave(void)
{
	MKMcast4 *elem;
	CString str;
	MAddressIP aiS, aiE;

	if(!WriteEmptyCommentLine()) return false;
	if(!WriteCommentLine(_T("CHScanner - Multicast IPv4 Addresses"))) return false;
	if(!WriteEmptyCommentLine()) return false;
	if(!WriteCommentLine(_T("Builded from the IANA's \"multicast-addresses.txt\" file"))) return false;
	if(!WriteCommentLine(_T("As stated there, the IANA's \"multicast-addresses.txt\" file was generated on 21 September 2006"))) return false;
	if(!WriteEmptyCommentLine()) return false;

	if(!WriteEmptyLine()) return false;

	for(itor=theVector.begin(); itor!=theVector.end(); itor++){
		elem = *itor;
		if(elem!=NULL){
			aiS.Set(elem->addrStart);
			aiE.Set(elem->addrEnd);
			str.Format(_T("%s-%s %s"), aiS.GetS(), aiE.GetS(), elem->assignedTo);
			if(!WriteLine(str)) return false;
		}
	}

	if(!WriteEmptyLine()) return false;

	return true;
}

//---------------------------------------------------------------------------
